/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.iecg.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.iecg.api.entity.IecgCheckCondition;
import com.iecg.api.entity.IecgCheckData;
import com.iecg.api.entity.IecgCheckReport;
import com.iecg.api.entity.IecgUser;
import com.iecg.dao.IecgCheckDataRepository;
import com.iecg.service.IecgCheckConditionService;
import com.iecg.service.IecgCheckDataService;
import com.iecg.service.IecgUserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import top.iecg.cascare.ZKHSCascare;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 *
 *
 * @author zjc
 * @date 2019-09-05 11:07:08
 */
@Service
@Slf4j
public class IecgCheckDataServiceImpl implements IecgCheckDataService {

	@Autowired
	private IecgCheckDataRepository checkDataRepository;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Autowired
	private IecgUserService iecgUserService;

	@Autowired
	private IecgCheckConditionService iecgCheckConditionService;

	public IecgCheckData save(IecgCheckData iecgCheckData) {
		iecgCheckData.setCreateDate(new Date());
		return checkDataRepository.save(iecgCheckData);
	}


	/**
	 * 保存心电测量数据
	 * @param iecgCheckDataList
	 * @return
	 */
	public Map saveList(List<IecgCheckData> iecgCheckDataList) {

		log.info(Arrays.toString(iecgCheckDataList.toArray()));

		IecgUser loginUser = iecgUserService.getSecurityUser();

		AtomicBoolean isWarnAnalysis = new AtomicBoolean(false);
		iecgCheckDataList.stream().forEach(iecgCheckData -> {

			Optional<IecgCheckData> optionalIecgCheckData= checkDataRepository.findIecgCheckDataByBizIdAndLeadType(iecgCheckData.getBizId(), iecgCheckData.getLeadType());
			if(optionalIecgCheckData.isPresent()){
				IecgCheckData iecgCheckDataGet = optionalIecgCheckData.get();
				Query query = new Query();
				Criteria criteria = new Criteria();
				query.addCriteria(Criteria.where("bizId").is(iecgCheckData.getBizId()));
				query.addCriteria(Criteria.where("leadType").is(iecgCheckData.getLeadType()));
				Update update = new Update();
				StringBuffer sb1 = new StringBuffer();
				sb1.append(iecgCheckDataGet.getEcgData()).append(",").append(iecgCheckData.getEcgData());
				update.set("ecgData", sb1.toString());
				StringBuffer sb2 = new StringBuffer();
				byte countGet = iecgCheckDataGet.getCount();
				sb2.append(iecgCheckDataGet.getTmpEcgData()).append(",").append(iecgCheckData.getEcgData());
				update.set("count", iecgCheckDataGet.getCount() + 1);
				int  interval = iecgCheckData.getInterval();
				int compare = 30 / interval;
				if(countGet == compare- 1 && !isWarnAnalysis.get()){
					isWarnAnalysis.set(true);
					update.set("endTime",System.currentTimeMillis());
				}
				if(countGet >= compare){
					sb2.setLength(0);
				    sb2.append(iecgCheckData.getEcgData());
					update.set("count", 1);
				}
				update.set("tmpEcgData", sb2.toString());
				mongoTemplate.updateFirst(query, update, "iecgCheckData");
			}else {
				iecgCheckData.setTmpEcgData(iecgCheckData.getEcgData());
				iecgCheckData.setCount((byte) 1);
				iecgCheckData.setId(null);
				iecgCheckData.setCreateDate(new Date());
				iecgCheckData.setGain(250);
				iecgCheckData.setSamplingRate(200);
				iecgCheckData.setZeroValue(2048);
				iecgCheckData.setUserId(loginUser.getId());
				int interval = iecgCheckData.getInterval();
				iecgCheckData.setStartTime(System.currentTimeMillis() - interval* 1000 );
				checkDataRepository.save(iecgCheckData);
			}

		});

		// 预警分析
		if(isWarnAnalysis.get()){
			IecgCheckData iecgCheckData = iecgCheckDataList.stream().findAny().get();
			String bizId = iecgCheckData.getBizId();
			IecgCheckCondition iecgCheckCondition = iecgCheckConditionService.findById(bizId).get();
			IecgUser iecgUser = iecgUserService.getById(iecgCheckCondition.getUserId());
			String sex = iecgUser.getSex();
			int gender =0;
			if(sex.equals("女") || sex.equals("2")){
				gender = 1;
			}
			int age = iecgUser.getAge();
			String result = warnAnalysis(bizId, gender, age);
			Map resultMap = new HashMap<>();
			resultMap.put("analysis", result);
			resultMap.put("startTime",iecgCheckData.getStartTime());
			resultMap.put("endTime",System.currentTimeMillis());
			resultMap.put("userName", iecgUser.getName());
			resultMap.put("gender", gender);
			resultMap.put("age", age);
			resultMap.put("outliers", iecgCheckData.getOutliers());
			resultMap.put("preConditon",iecgCheckCondition);
			return resultMap;
		}
		return null;
	}


	public Optional<IecgCheckData> findById(String id) {
		return checkDataRepository.findById(id);
	}

	public Page<IecgCheckData> page(Pageable pageable, IecgCheckData iecgCheckData) {
		Query query = new Query();

		//动态拼接查询条件
//		if (!StringUtils.isEmpty(studentReqVO.getName())){
//			Pattern pattern = Pattern.compile("^.*" + studentReqVO.getName() + ".*$", Pattern.CASE_INSENSITIVE);
//			query.addCriteria(Criteria.where("name").regex(pattern));
//		}

		if (iecgCheckData.getBizId() != null){
			query.addCriteria(Criteria.where("bizId").is(iecgCheckData.getBizId()));
		}

		if (iecgCheckData.getUserId() != null){
			query.addCriteria(Criteria.where("userId").is(iecgCheckData.getUserId()));
		}

		//计算总数
		long total = mongoTemplate.count(query, IecgCheckReport.class);

		//查询结果集
		List<IecgCheckData> resultList = mongoTemplate.find(query.with(pageable), IecgCheckData.class);
		Page<IecgCheckData> pages = new Page(pageable.getPageNumber(), pageable.getPageSize(), total);
		pages.setRecords(resultList);
		pages.setSearchCount(true);
		return pages;
	}

	public IecgCheckData modifyCheckData(IecgCheckData checkData) {
		return checkDataRepository.save(checkData);
	}

	public void deleteCheckData(String id) {
		checkDataRepository.deleteById(id);
	}

	public List<IecgCheckData> findAllByBizId(String bizId) {
		return checkDataRepository.findAllByBizId(bizId).get();
	}

	public Optional<IecgCheckData> findByBizId(String bizId) {
		return checkDataRepository.findIecgCheckDataByBizId(bizId);
	}


	/**
	 * 预警分析
	 * @param bizId
	 * @return
	 */
	@SneakyThrows
	private String  warnAnalysis(String bizId, Integer gender, Integer age){

		gender = 0;
		age = 41;
		//---------------------------------------------------------
		List<IecgCheckData> ecgDataList = findAllByBizId(bizId);
		int signalsNum = ecgDataList.size();
		int zeroValue = ecgDataList.get(0).getZeroValue();
		int gain = ecgDataList.get(0).getGain();
		int[] feeling={0,0,0,0,0};//检测前填写的体格检查
		int[] abnormalPoint={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//测试过程中用户异常打卡点,采样点的序号

		int[] fss=new int[signalsNum];
		double[] gains=new double[signalsNum];
		double[] zerovalue=new double[signalsNum];
		StringBuffer buf = new StringBuffer();
		for(int i=0; i< signalsNum; i++){
			if(i>0){
				buf.append("|");
			}
			buf.append(ecgDataList.get(i).getLeadType());
			fss[i]= ecgDataList.get(i).getSamplingRate();
			gains[i]= ecgDataList.get(i).getGain();
			zerovalue[i]=ecgDataList.get(i).getZeroValue();
		}
		double[][] multiEcgData = new double[signalsNum][];

		int samples= 0;
		for(int i = 0 ; i < signalsNum ; i++ ){
			String tmpEcgData = ecgDataList.get(i).getTmpEcgData();
			if(tmpEcgData == null){
				return null;
			}
			String[]  tmpArray = tmpEcgData.split(",");
			Double[]  tmpEcgDataArray = Arrays.stream(tmpArray).map(cell ->
					(Double.valueOf(cell)- zeroValue) / gain).toArray(Double[]::new);
			multiEcgData[i] = ArrayUtils.toPrimitive(tmpEcgDataArray);
			samples = tmpArray.length;
		}
		log.info("multEcgData{}, singleNum{}, samples{}, fss{}, gains{}, zerovalue{}, buf{}, age{}, gender{}, feeling{}, abnormalPoint{}",
				Arrays.toString(multiEcgData), signalsNum, samples, Arrays.toString(fss),Arrays.toString(gains), Arrays.toString(zerovalue), buf.toString(), age, gender, Arrays.toString(feeling),Arrays.toString(abnormalPoint));
		log.info("开始生成分析预警报告..................");
		String result = ZKHSCascare.ecgAnalysisEcgfeatures(multiEcgData, signalsNum, samples, fss, gains, zerovalue, buf.toString(), age, gender, feeling, 5, abnormalPoint, 20);
		return result;
	}
}
